const Controller = require("egg").Controller;
const crypto = require('crypto');

module.exports = class CallController extends Controller {

  async proxy(){
    const ctx = this.ctx;
    const body = await ctx.parseBody();
    const token = await this.ensureToken();
    if (!token) {
      ctx.throw(401);
    }
    const r = await ctx.api.aliyunProxy.post('/proxy', {
        region: 'cn-shanghai',
        endpoint: "CCC",
        product: "CCC",
        domain: "ccc.cn-shanghai.aliyuncs.com",
        version: "2017-07-05",
        accessToken: token.access_token,
        action: ctx.query.action,
        request: body && body.request && JSON.parse(body.request) || undefined
      }
    )
    ctx.body = r;
  }

  async login(){
    const token = await this.ensureToken();
    if (token) {
      this.ctx.body = {
        code: 0,
        data: false
      };
      return;
    }
    const r = this.ctx.query.r || "/";
    const nonce = crypto.randomBytes(32).toString('hex').substr(0, 45);
    const url = "https://signin.aliyun.com/oauth2/v1/auth?" +
      [
        `response_type=code`,
        `response_mode=form_post`,
        `redirect_uri=${ encodeURIComponent(`${this.ctx.origin}/_api/call/redirect?r=${ encodeURIComponent(r) }&n=${nonce}`) }`,
        `state=${Math.random().toString().substr(-4)}`,
        `codeChallenge=${nonce}`,
        `access_type=offline`,
        `client_id=${this.config.call.clientId}`
      ].join("&")
    this.ctx.body = {
      code: 0,
      data: url
    };
  }

  async redirect(){
    const ctx = this.ctx;
    const {
      id_token,
      access_token,
      refresh_token,
      expires_in
    } = await this.ctx.api.aliyunOauth.post("/token", {
      client_id: this.config.call.clientId,
      client_secret: this.config.call.clientSecret,
      grant_type: 'authorization_code',
      code: ctx.query.code,
      redirect_uri: `${ctx.origin}/_api/call/redirect?r=${ encodeURIComponent(ctx.query.r) }&n=${ctx.query.n}`,
      code_verifier: ctx.query.n
    });
    const expire_at = Date.now() + expires_in * 1000 - (/* 提前5分钟让token失效以防止服务器时间不一致导致验证问题 */ 300 * 1000);
    const token = { id_token, access_token, refresh_token, expire_at };
    this.logger.info("got access token", token);
    ctx.session.aliyunToken = token;
    ctx.redirect(ctx.query.r || '/');
  }

  async logout(){
    const ctx = this.ctx;
    const token = this.getToken();
    if (token) {
      try {
        const { id_token, access_token, refresh_token } = token;
        await this.ctx.api.aliyunOauth.post("/revoke", {
          client_id: this.config.call.clientId,
          client_secret: this.config.call.clientSecret,
          token: access_token
        });
        this.logger.info("aliyun token", access_token, "revoked");
      } catch (e) {
        /* 销毁token请求即使失败也不报错 */
        this.logger.warn("logout ignore error", e);
      }
    }
    this.logger.info("clear aliyunToken");
    ctx.session.aliyunToken = null;
    const r = ctx.query.r || '/';
    ctx.redirect(r);
  }

  getToken(){
    const data = this.ctx.session.aliyunToken;
    if (!data) return null;
    try {
      let { id_token, access_token, refresh_token, expire_at } = data;
      if (!id_token || !access_token || !refresh_token || !expire_at) {
        return null;
      }
      return { id_token, access_token, refresh_token, expire_at };
    } catch (e) {
      /* Cookie获取失败或格式错误，认为是未登录，不抛出异常 */
      this.logger.warn("getToken ignore error", e);
      return null;
    }
  }

  async ensureToken(){
    try {
      const token = this.getToken();
      if (!token) return null;
      let { id_token, access_token, refresh_token, expire_at } = token;
      if (Date.now() < expire_at/*有效期内*/) {
        return { id_token, access_token };
      }
      /* 过有效期，需要刷新 */
      const refreshData = await this.ctx.api.aliyunOauth.post("/token", {
        client_id: this.config.call.clientId,
        client_secret: this.config.call.clientSecret,
        refresh_token,
        grant_type: 'refresh_token'
      });
      access_token = refreshData.access_token;
      expire_at = Date.now() + refreshData.expires_in * 1000 - (/* 提前5分钟让token失效以防止服务器时间不一致导致验证问题 */ 300 * 1000);
      const newtoken = { id_token, access_token, refresh_token, expire_at };
      this.logger.info("update aliyunToken");
      this.ctx.session.aliyunToken = newtoken;
      return { id_token, access_token };
    } catch (e) {
      /* Cookie获取失败或刷新失败，认为是未登录，不抛出异常 */
      this.logger.warn("ensureToken ingore error", e);
      this.logger.info("clear aliyunToken");
      this.ctx.session.aliyunToken = null;
      return null;
    }
  }

  async comm(ctx){
    let senddata  = await ctx.parseBody()
    let url = ctx.url
    console.log('comm data:',senddata)
    console.log('comm url:',url)
    // const result = await this.ctx.api.aliyunOauth.post("/www.sobot.com/comm/oauth/token", {
    let result = await ctx.curl('www.sobot.com'+url,{
        method:'POST',
        data:senddata,
        dataType: 'json',
    })
    console.log('result:',result)
    ctx.body=result.data
  }
  async agent(ctx){
    let senddata  = await ctx.parseBody()

    let url = ctx.url
    console.log('agentcomm data:',JSON.stringify(senddata),ctx.request.body)
    console.log('agentcomm url:',url)
    // const result = await this.ctx.api.aliyunOauth.post("/www.sobot.com/comm/oauth/token", {
    let result = await ctx.curl('www.sobot.com'+url,{
        method:'POST',
        data:senddata,
        dataType: 'json',
        contentType:'json'
    })
    console.log('agentresult:',result)
    ctx.body=result.data
  }
}
